package com.fdb.efp.nls.service.impl.dxm;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

import com.fdb.efp.nls.service.facade.dxm.LimitSoltService;
import com.fdb.efp.nls.service.facade.queue.NlsProcessBizService;
import com.fdb.efp.nls.service.vo.queue.NlsProcessBizVO;
import org.apache.logging.log4j.ThreadContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.fdb.basic.framework.core.exception.BizException;
import com.fdb.basic.framework.core.exception.HangException;
import com.fdb.basic.framework.core.threadpool.AbstractThreadTask;
import com.fdb.basic.framework.core.threadpool.ExecuteRtnInfo;
import com.fdb.basic.framework.core.util.DateUtility;
import com.fdb.basic.framework.core.util.SpringContextUtils;
import com.fdb.basic.framework.core.util.TraceUtil;
import com.fdb.efp.nls.service.facade.PrdAdaptedSoltService;
import com.fdb.efp.nls.service.vo.PrdAdaptedSoltVO;
import com.fdb.efp.esb.common.constant.dxm.DxmEnum;
import com.fdb.efp.limit.service.facade.LmtAdjustThirdService;
import com.fdb.efp.limit.service.vo.LmtAdjustThirdVO;
import com.fdb.efp.nls.common.constant.PrdAdaptedSoltEnums;
import com.fdb.efp.nls.common.constant.QueueTaskEnums;
import com.fdb.efp.nls.common.util.PrdQueueSlotUtils;

/**
  * 额度调整申请队列
  * @author  qiuyf
  * @since 2019年3月12日 下午3:40:44
  * @version 1.0
 */
@Service("queueHandleLimitService")
@Scope(scopeName = "prototype")
public class QueueHandleLimit extends AbstractThreadTask {
	private static Logger logger = LoggerFactory.getLogger(QueueHandleLimit.class);

	private LmtAdjustThirdVO lmtAdjustThirdVo;

	public void setLmtAdjustThirdVO(LmtAdjustThirdVO lmtAdjustThirdVo) {
		this.lmtAdjustThirdVo = lmtAdjustThirdVo;
	}

	@Override
	public ExecuteRtnInfo call() throws Exception {
		this.doTask();
		return new ExecuteRtnInfo(null, null, null, null, true);
	}

	/**
	 * 根据申请信息中产品信息查询产品适配插槽表，获取该产品待执行的插槽;<br>
	 * 判断该插槽状态，如果是待执行，则执行对应的服务；如果是已挂起的，则重跑；
	 */
	@Override
	public void doTask() throws HangException, BizException, Exception {
		TraceUtil.setTraceId(lmtAdjustThirdVo.getGlobalSerno());
		TraceUtil.setPlafmID(lmtAdjustThirdVo.getPlatfmid());
		TraceUtil.setPlafmUsrID(lmtAdjustThirdVo.getPlatfmusrid());
		ThreadContext.put(TraceUtil.GLBLSRLNO, lmtAdjustThirdVo.getGlobalSerno());
		logger.info("*********************************************");
		logger.info("*            开始一笔新的执行队列                 * ");
		logger.info("*********************************************");
		logger.info("* 申请流水号:【" + lmtAdjustThirdVo.getAdjAmtId() + "】*");
		logger.info("* 客户编号 : 【" + lmtAdjustThirdVo.getCusId() + "】*");
		logger.info("* 客户名称 : 【" + lmtAdjustThirdVo.getCusName() + "】*");
		logger.info("* 产品ID:  【" + lmtAdjustThirdVo.getPrdId() + "】*");
		logger.info("* 产品代码: 【" + lmtAdjustThirdVo.getPrdCode() + "】*");
		logger.info("* 产品名称 : 【" + lmtAdjustThirdVo.getPrdName() + "】*");
		logger.info("* 创建时间 : 【" + lmtAdjustThirdVo.getCreateTime() + "】*");
		logger.info("*********************************************");
		String applySeq = lmtAdjustThirdVo.getAdjAmtId();
		try {
			logger.info("根据产品ID、插槽阶段和插槽状态查询产品插槽信息");
			PrdAdaptedSoltVO prdAdaptedSoltVo = new PrdAdaptedSoltVO();
			prdAdaptedSoltVo.setPrdId(lmtAdjustThirdVo.getPrdId());
			prdAdaptedSoltVo.setSoltStage(lmtAdjustThirdVo.getSoltStage());// 插槽阶段
			prdAdaptedSoltVo.setSoltState(PrdAdaptedSoltEnums.SlotStateEnum.ON.getCode());// 插槽状态
			List<PrdAdaptedSoltVO> prdAdaptedSoltVoList = prdAdaptedSoltService.queryByPrdIdAndState(prdAdaptedSoltVo);
			Objects.requireNonNull(prdAdaptedSoltVoList);

			logger.info("根据申请流水号:【" + applySeq + "】查询网贷业务过程信息");
			NlsProcessBizVO nlsProcessBizVo = new NlsProcessBizVO();
			nlsProcessBizVo.setApplySeq(applySeq);
			nlsProcessBizVo = nlsProcessBizService.queryByPk(nlsProcessBizVo);
			Objects.requireNonNull(nlsProcessBizVo);
			/** 性能调优迁移代码 author：wangyk date:20190219 start **/
			Method method = null;
			for (int i = 0; i < prdAdaptedSoltVoList.size(); i++) {
				PrdAdaptedSoltVO prdAdaptedSolt = prdAdaptedSoltVoList.get(i);
				String prdId = prdAdaptedSolt.getPrdId();
				String soltCode = prdAdaptedSolt.getSoltCode();
				String soltName = prdAdaptedSolt.getSoltName();
				String soltStage = prdAdaptedSolt.getSoltStage();
				String soltService = prdAdaptedSolt.getSoltService();// 插槽服务类，此处指注册到dubbo中的实现类
				int soltOrder = prdAdaptedSolt.getSoltOrder();
				// 校验产品插槽中的产品ID、插槽代码、插槽名称、插槽服务和顺序是否正确，不正确则抛出异常
				boolean checkFlag = PrdQueueSlotUtils.checkAdaptedSoltInfo(prdId, soltCode, soltName, soltService, soltStage, soltOrder);
				if (!checkFlag) {
					logger.error("产品插槽中的产品ID【" + prdId + "】插槽代码【" + soltCode + "】插槽名称【" + soltName + "】插槽服务【" + soltService + "】插槽阶段【" + soltStage + "】和顺序【"
							+ soltOrder + "】错误，请检查.");
					throw new Exception("产品插槽中的产品ID【" + prdId + "】插槽代码【" + soltCode + "】插槽名称【" + soltName + "】插槽服务【" + soltService + "】插槽阶段【" + soltStage + "】和顺序【"
							+ soltOrder + "】错误，请检查.");
				}
				/** 更新执行状态为待执行 **/
				method = nlsProcessBizVo.getClass().getMethod("setSoltState" + soltOrder, String.class);
				method.invoke(nlsProcessBizVo, PrdAdaptedSoltEnums.SoltProcessStateEnum.EXECUTORY.getCode());
			}
			nlsProcessBizService.updateByPk(nlsProcessBizVo);
			/** 性能调优迁移代码 author：wangyk date:20190219 end **/
			logger.info("申请流水号:【" + applySeq + "】的遍历产品插槽的信息开始");
			for (int i = 0; i < prdAdaptedSoltVoList.size(); i++) {
				PrdAdaptedSoltVO prdAdaptedSolt = prdAdaptedSoltVoList.get(i);
				String prdId = prdAdaptedSolt.getPrdId();
				String soltCode = prdAdaptedSolt.getSoltCode();
				String soltName = prdAdaptedSolt.getSoltName();
				String soltStage = prdAdaptedSolt.getSoltStage();
				String soltService = prdAdaptedSolt.getSoltService();// 插槽服务类，此处指注册到dubbo中的实现类
				int soltOrder = prdAdaptedSolt.getSoltOrder();
				// 校验产品插槽中的产品ID、插槽代码、插槽名称、插槽服务和顺序是否正确，不正确则抛出异常
				boolean checkFlag = PrdQueueSlotUtils.checkAdaptedSoltInfo(prdId, soltCode, soltName, soltService, soltStage, soltOrder);
				if (!checkFlag) {
					logger.error("产品插槽中的产品ID【" + prdId + "】插槽代码【" + soltCode + "】插槽名称【" + soltName + "】插槽服务【" + soltService + "】插槽阶段【" + soltStage + "】和顺序【"
							+ soltOrder + "】错误，请检查.");
					throw new Exception("产品插槽中的产品ID【" + prdId + "】插槽代码【" + soltCode + "】插槽名称【" + soltName + "】插槽服务【" + soltService + "】插槽阶段【" + soltStage + "】和顺序【"
							+ soltOrder + "】错误，请检查.");
				}
				// 根据插槽代码 映射
				Method methodSoltName = nlsProcessBizVo.getClass().getMethod("setSoltName" + soltOrder, String.class);
				Method methodSoltTime = nlsProcessBizVo.getClass().getMethod("setSoltTime" + soltOrder, String.class);

				nlsProcessBizVo.setSoltCode(soltCode);// 插槽代码
				nlsProcessBizVo.setSoltName(soltName);// 插槽名称
				nlsProcessBizVo.setSoltService(soltService);// 插槽服务类
				nlsProcessBizVo.setExceptionFlag(Boolean.FALSE);// 异常标志
				nlsProcessBizVo.setQueueTaskState(QueueTaskEnums.QueueTaskStateEnum.EXECUTING.getCode());
				nlsProcessBizService.updateByPk(nlsProcessBizVo);

				// 更新当前插槽代码、当前插槽名称
				/** 当前插槽代码 */
				lmtAdjustThirdVo.setSoltCode(soltCode);
				/** 当前插槽名称 */
				lmtAdjustThirdVo.setSoltName(soltName);
				/** 插槽名称 */
				methodSoltName.invoke(nlsProcessBizVo, soltName);
				/** 插槽开始时间 */
				methodSoltTime.invoke(nlsProcessBizVo, DateUtility.getCurrAppDateTimeString());
				/** 更新申请进件信息 */
				lmtAdjustThirdService.updateByPk(lmtAdjustThirdVo);

				logger.info("根据插槽服务 ：【" + soltService + "】映射处理Bean开始");
				LimitSoltService slotServiceBean = (LimitSoltService) SpringContextUtils.getBean(soltService);
				logger.info("根据插槽服务 ：【" + soltService + "】映射处理Bean结束，该对象为：【" + slotServiceBean + "】，调用对应的服务开始。");
				slotServiceBean.execute(nlsProcessBizVo, lmtAdjustThirdVo, soltOrder);
				logger.info("根据插槽服务 ：【" + soltService + "】映射处理Bean结束，该对象为：【" + slotServiceBean + "】，调用对应的服务结束。");
			}
			logger.info("申请流水号:【" + applySeq + "】的遍历产品插槽的信息结束");

			logger.info("根据申请流水号:【" + applySeq + "】更新业务流程表队列任务状态为执行成功开始");
			nlsProcessBizVo.setQueueTaskState(QueueTaskEnums.QueueTaskStateEnum.SUCCESS.getCode());

			logger.info("根据申请流水号:【" + applySeq + "】更新网贷任务队列中队列任务状态为执行成功开始");

			/** 设置插槽结果信息 **/
			lmtAdjustThirdVo.setSoltResultDetails(JSONObject.toJSONString(nlsProcessBizVo));
			/** 设置结果码 **/
			lmtAdjustThirdVo.setRspCode(QueueTaskEnums.RspInfoEnum.SUCCESS.getRspCode());
			/** 设置结果信息 **/
			lmtAdjustThirdVo.setRspMsg(QueueTaskEnums.RspInfoEnum.SUCCESS.getRspMsg());
			/** 设置申请状态信息为通过 **/
			lmtAdjustThirdVo.setAdjStatus(DxmEnum.LoanAdjustSts.PASS.getVALUE());
			/** 设置申请最近修改时间 **/
			lmtAdjustThirdVo.setLastUpdateTime(DateUtility.getCurrAppDateTimeString());

			lmtAdjustThirdService.updateByPk(lmtAdjustThirdVo);
			logger.info("根据申请流水号:【" + applySeq + "】更新 申请进件信息中申请状态为通过结束");
			
			nlsProcessBizService.updateByPk(nlsProcessBizVo);
			logger.info("根据申请流水号:【" + applySeq + "】更新业务流程表队列任务状态为执行成功结束");
		} catch (HangException e) {
			logger.error("队列处理服务中申请流水号:【" + applySeq + "】的挂起异常信息为：" + e.getMessage());
			throw e;
		} catch (BizException e) {
			logger.error("队列处理服务中申请流水号:【" + applySeq + "】的业务异常信息为：" + e.getMessage());
			throw e;
		} catch (Exception e) {
			logger.error("队列处理服务中申请流水号:【" + applySeq + "】的其他异常信息为：" + e.getMessage());
			throw e;
		} finally {
			TraceUtil.clear();
		}
	}

	@Autowired
	@Qualifier("prdAdaptedSoltService")
	private PrdAdaptedSoltService prdAdaptedSoltService;
	@Autowired
	@Qualifier("nlsProcessBizService")
	private NlsProcessBizService nlsProcessBizService;
	@Autowired
	@Qualifier("lmtAdjustThirdService")
	private LmtAdjustThirdService lmtAdjustThirdService;

}
